#ifndef SCHEDULER_H
#define SCHEDULER_H

using namespace std;

//  Return codes
const int SRET_SUCCESS             = 0; // No errors, ready for next
                                        // execution

const int SRET_CS_PF               = 1; // Context Switch or Page Fault: check ref bits

const int SRET_NO_ACTIVE_PROCESSES = 2; // All procs blocked

const int SRET_NO_PROCESSES        = 3; // No processes remain (end condition)

const int SRET_CS_PF_DIRTY         = 4; // Context Switch or Page Fault 
                                        // with removal of dirty frame (cost of 20)

const int SRET_ERROR               = -1; // Assorted error, end execution



// Round-Robin TimeSlice
const int TIME_SLICE = 10;

struct ProcessReturn {
  int ret;
};
struct SchedulerReturn {
 int return_code;
};

class Scheduler {
 private:
   int RR_Time;
   queue<int> ActiveQueue;
   map<int,Process*> ActiveProcesses;
   map<int,Process*> WaitingProcesses;
   map<int,int> waitingList;
   vector<int> unblockList;
   set<int> pidSet;
   Process* currentProcess;
   int currentPid;
   int tempPid;
   PageTable* pt;
   TLB* tlb;
   MMU* mmu;
   MM* mm;
   int contextSwitchTime;
   int counter;
   int prevProcess;

   // For Analysis
   int PageFaultCount;
   int SwitchCount;

 public:
   Scheduler();
   int run(int tick);
   map<int,Process*> getActiveProcesses()
   {
     return ActiveProcesses;
   }
   map<int,Process*> getWaitingProcesses()
   {
     return WaitingProcesses;
   }   
   int checkBlockedList(int itick);
   int AddProcess(int ipid,Process* p);
   int UnblockProcess(int ipid);
   int getPid();
   int switchProcesses(int itick);
   PageTable* returnPageTable() { return pt; };
   MMU* returnMMU() { return mmu; };
   void setBaseBound();
   void refBitLRUApprox(int itick);

   // For Analysis
   int returnPageFaultCount() { return PageFaultCount; };
   int returnSwitchCount() { return SwitchCount; };
};

#endif
